콜 스택
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.
1. 개요
콜 스택은 서브루틴 호출과 관련된 정보를 저장하는 데 사용되는 자료 구조이다. 콜 스택의 주요 기능은 반환 주소, 지역 변수 및 매개변수 저장, 평가 스택, 둘러싸는 서브루틴 컨텍스트 등을 저장하는 것이다. 콜 스택은 스택 프레임으로 구성되며, 각 스택 프레임은 서브루틴의 상태 정보를 담고 있다. 스택 포인터와 프레임 포인터 레지스터를 사용하여 스택 프레임 내의 정보에 접근하며, 함수 호출과 반환 시 스택 프레임이 생성 및 제거된다. 재귀 호출과 스레드 안전성을 지원하며, 중첩 함수를 구현하는 데 사용되기도 한다. 콜 스택은 프로그램 성능 프로파일링에 활용될 수 있으며, 스택 버퍼 오버플로우와 같은 보안 취약점을 야기할 수 있다.
더 읽어볼만한 페이지
- 함수 (프로그래밍) - 사용자 정의 함수
사용자 정의 함수는 프로그래밍 언어와 데이터베이스 시스템에서 사용자가 직접 정의하여 재사용할 수 있는 코드 블록이다. - 함수 (프로그래밍) - 코루틴
코루틴은 실행을 멈췄다가 다시 시작할 수 있는 서브루틴의 특별한 형태로, 로컬 데이터를 보존하며 다양한 방식으로 구현되고 여러 프로그래밍 상황에서 유용하게 쓰인다. - 메모리 관리 - 동적 메모리 할당
동적 메모리 할당은 프로그램 실행 중 힙 영역에서 메모리 공간을 확보 및 해제하여 효율적인 메모리 관리와 유연성을 제공하는 기술로, 메모리 누수 방지 및 가비지 컬렉션 등의 고려 사항이 중요하며 C, C++, C++/CLI, C# 등에서 사용된다. - 메모리 관리 - 정적 변수
정적 변수는 프로그램 실행 시간 동안 값을 유지하며, C 언어에서 `static` 키워드로 정의되어 함수 호출 간에 값을 유지하고, 객체 지향 프로그래밍에서 클래스의 모든 인스턴스에서 공유되는 클래스 변수로 사용된다. - 컴퓨터에 관한 - 고속 패킷 접속
고속 패킷 접속(HSPA)은 3세대 이동통신(3G)의 데이터 전송 속도를 높이는 기술 집합체로, 고속 하향/상향 패킷 접속(HSDPA/HSUPA)을 통해 속도를 개선하고 다중 안테나, 고차 변조, 다중 주파수 대역 활용 등의 기술로 진화했으나, LTE 및 5G 기술 발전으로 현재는 상용 서비스가 중단되었다. - 컴퓨터에 관한 - 데이터베이스
데이터베이스는 여러 사용자가 공유하고 사용하는 정보의 집합으로, 데이터베이스 관리 시스템을 통해 접근하며, 검색 및 갱신 효율을 높이기 위해 고도로 구조화되어 있고, 관계형, NoSQL, NewSQL 등 다양한 모델로 발전해왔다.
콜 스택 | |
---|---|
자료 구조 | |
종류 | 자료 구조 |
개요 | |
정의 | 컴퓨터 프로그램의 서브루틴이 호출될 때 서브루틴의 복귀 주소와 변수 값 등을 저장하는 스택 프레임 형태의 자료 구조 |
용도 | 프로그램 실행 흐름을 추적하고, 함수 호출 및 반환을 관리하는 데 사용 |
동작 원리 | |
스택 프레임 | 함수 호출 시 생성되는 스택 영역으로, 복귀 주소, 매개변수, 지역 변수 등을 저장 |
푸시 (Push) | 함수 호출 시 스택 프레임을 스택에 추가하는 동작 |
팝 (Pop) | 함수 반환 시 스택 최상단의 스택 프레임을 제거하는 동작 |
스택 포인터 | 스택의 최상단을 가리키는 포인터로, 푸시 및 팝 연산 시 갱신됨 |
활용 | |
함수 호출 | 함수 호출 시 복귀 주소를 스택에 저장하여 함수 실행 후 원래 위치로 돌아갈 수 있도록 함 |
지역 변수 관리 | 함수 내에서 선언된 지역 변수를 스택에 저장하여 함수 간 변수 충돌을 방지 |
예외 처리 | 예외 발생 시 스택 정보를 이용하여 예외 처리 루틴을 찾고, 프로그램 상태를 복구 |
재귀 호출 | 재귀 함수 호출 시 각 호출에 대한 스택 프레임을 스택에 저장하여 재귀 호출을 관리 |
장점 | |
효율적인 메모리 관리 | 함수 호출 시에만 메모리를 할당하고, 반환 시 자동으로 해제하므로 메모리 낭비를 줄임 |
간단한 구현 | 스택 자료 구조를 이용하여 간단하게 구현 가능 |
단점 | |
스택 오버플로 | 스택 크기 제한으로 인해 함수 호출이 너무 많거나, 큰 크기의 지역 변수를 사용할 경우 스택 오버플로 발생 가능 |
제한된 접근 | 스택의 중간에 있는 데이터에 직접 접근이 불가능 |
구현 방식 | |
하드웨어 스택 | CPU 내부에 구현된 스택으로, 빠른 속도로 동작 |
소프트웨어 스택 | 메모리 영역에 구현된 스택으로, 유연하게 크기 조절 가능 |
프로그래밍 언어별 지원 | |
C/C++ | 컴파일러가 스택을 이용하여 함수 호출 및 반환을 처리 |
Java | JVM (Java Virtual Machine)이 스택을 이용하여 메소드 호출 및 반환을 처리 |
Python | 인터프리터가 스택을 이용하여 함수 호출 및 반환을 처리 |
2. 역사
콜 스택은 서브루틴이 처리를 완료하고 제어를 반환할 때 어디로 돌아가야 하는지를 기억하는 것이 주된 목적이다. 콜 스택은 스택으로 구성되어 호출 측은 반환 주소를 스택에 'push'하고, 호출된 서브루틴이 완료되면 반환 주소를 콜 스택에서 'pop'하여 해당 주소로 제어를 반환한다.
콜 스택은 스택 자료구조를 기반으로 동작하며, 함수 호출 시 반환 주소, 지역 변수, 매개변수 등을 저장하는 데 사용된다. 함수가 호출되면 해당 함수의 정보(반환 주소, 지역 변수 등)가 콜 스택에 푸시되고, 함수 실행이 완료되면 해당 정보가 팝되어 이전 상태로 복귀한다. 이러한 과정을 통해 프로그램의 실행 흐름을 제어하고 함수 간의 관계를 관리한다.[7]
저수준 언어(어셈블리 언어)에서는 프로그래머가 명시적으로 스택을 조작해야 한다. 반면, 고수준 언어에서는 콜 스택이 투명하여, 프로그래머가 콜 스택의 존재를 의식하지 않고 호출 계층 구조에 의해 실현되는 상위 개념으로서의 프로그램 로직에만 집중할 수 있다. 식별자를 사용한 서브루틴(함수) 호출은 언어 처리 시스템에 의해 해당 주소로의 점프 명령으로 해결되며, 스택에 반환 주소 저장이나 반환 주소로의 복귀와 같은 하위 레벨의 전처리·후처리도 숨겨진다. x86의 call과 ret처럼, 어셈블러 레벨에서도 하위 레벨의 스택 조작을 숨기는 명령이 준비되어 있는 아키텍처도 있다.
각 프로그래밍 언어에서의 스택 상세 정보는 컴파일러, 운영 체제(OS), 명령어 집합 등에 의존한다.
3. 기능
일반적으로 실행 중인 프로그램의 태스크 또는 스레드마다 하나씩 존재한다. 고급 프로그래밍 언어에서는 콜 스택의 세부 사항이 프로그래머에게 숨겨져 있지만, 어셈블리 언어에서는 프로그래머가 직접 스택을 조작해야 한다. 콜 스택의 구체적인 동작 방식은 컴파일러, 운영 체제, 명령 집합에 따라 달라진다.
콜 스택에 할당된 공간이 모두 소모되면 스택 오버플로 오류가 발생하며, 이 경우 프로그램이 크래시될 수 있다.
3. 1. 반환 주소 저장
서브루틴이 호출될 때, 호출한 함수로 돌아갈 위치(반환 주소)는 콜 스택에 저장된다. 서브루틴 실행이 완료되면 콜 스택에서 반환 주소를 빼내어 해당 주소로 복귀하여 실행을 계속한다.[7]
호출된 서브루틴이 또 다른 서브루틴을 호출하면, 새로운 반환 주소를 콜 스택에 푸시하여 정보가 쌓인다. 푸시 작업이 콜 스택에 할당된 공간을 모두 사용하면 스택 오버플로 오류가 발생하여 프로그램이 크래시될 수 있다.
콜 스택의 주요 목적은 반환 주소를 저장하는 것이다. 스택을 사용하여 반환 주소를 저장하면 다음과 같은 이점이 있다.3. 2. 지역 변수 및 매개변수 저장
서브루틴은 자신만의 지역 변수를 저장할 공간이 필요하다. 지역 변수는 해당 서브루틴 내에서만 사용되고, 서브루틴이 종료되면 더 이상 유지되지 않는다. 이러한 지역 변수를 저장하는 데 콜 스택이 사용된다. 스택의 맨 위를 조금 이동시키는 것만으로 공간을 확보할 수 있어, 힙 공간을 사용하는 동적 메모리 할당보다 훨씬 빠르다. 서브루틴이 호출될 때마다, 각 호출에 대한 지역 변수들이 콜 스택에 별도로 저장되므로, 서로 다른 호출 간에 간섭이 발생하지 않는다.
서브루틴은 호출하는 쪽에서 제공하는 매개변수 값을 저장할 공간도 필요하다. 보통 작은 개수의 매개변수는 프로세서 레지스터를 통해 전달되지만, 매개변수가 많아지면 메모리 공간이 필요하게 된다. 이때 콜 스택이 이러한 매개변수를 저장하는 공간으로 활용된다. 각 서브루틴 호출마다 매개변수 값이 콜 스택에 별도로 저장되므로, 서로 다른 호출 간에 매개변수 값이 섞이지 않는다. C++과 같은 객체 지향 언어에서는 매개변수 목록에 `this` 포인터도 포함될 수 있다.[7]
3. 3. 재귀 호출 지원
Call stack영어은 재귀 호출을 지원하는 데 필수적이다. 함수가 자기 자신을 호출하면, 각 호출마다 새로운 스택 프레임이 생성되어 반환 주소와 지역 변수를 저장한다. 함수가 종료되면 해당 프레임이 스택에서 제거되고, 저장된 반환 주소를 사용하여 이전 호출 지점으로 돌아간다. 이러한 방식으로 함수 호출의 깊이에 제한 없이 재귀 호출을 사용할 수 있다.[7]
3. 4. 중첩 함수 지원 (정적 스코프)
일부 프로그래밍 언어(예: 파스칼, 에이다)는 중첩 서브루틴의 선언을 지원하는데, 이는 둘러싸는 루틴의 컨텍스트(외부 루틴 범위 내의 매개변수 및 지역 변수)에 접근할 수 있다. 이러한 정적 중첩은 함수 내에 선언된 함수 내에 선언된 함수처럼 반복될 수 있다. 구현은 주어진 정적 중첩 레벨에서 호출된 함수가 각 둘러싸는 중첩 레벨에서 둘러싸는 프레임을 참조할 수 있는 수단을 제공해야 한다. 이 참조는 일반적으로 "다운스택 링크" 또는 "정적 링크"라고 하는 둘러싸는 함수의 가장 최근 활성화 인스턴스의 프레임에 대한 포인터로 구현되어, 즉각적인 호출자(정적 부모 함수일 필요는 없음)를 참조하는 "동적 링크"와 구별된다.[3]
정적 링크 대신, 둘러싸는 정적 프레임에 대한 참조는 원하는 프레임을 찾기 위해 인덱싱된 '디스플레이'라고 하는 포인터 배열로 수집될 수 있다. 루틴의 렉시컬 중첩의 깊이는 알려진 상수이므로 루틴의 디스플레이 크기는 고정된다. 또한, 순회해야 하는 포함하는 범위의 수가 알려져 있으므로 디스플레이에 대한 인덱스도 고정된다. 일반적으로 루틴의 디스플레이는 자체 스택 프레임에 있지만, Burroughs B6500은 최대 32개의 정적 중첩 레벨을 지원하는 하드웨어에서 이러한 디스플레이를 구현했다.
포함하는 범위를 나타내는 디스플레이 항목은 호출자의 디스플레이의 적절한 접두사에서 가져온다. 재귀하는 내부 루틴은 각 호출에 대해 별도의 콜 프레임을 생성한다. 이 경우, 내부 루틴의 모든 정적 링크는 동일한 외부 루틴 컨텍스트를 가리킨다.
내부 함수가 캡슐화에서 (상수가 아닌) 로컬 데이터에 접근하지 않는 경우, 예를 들어 인수와 반환 값을 통해서만 통신하는 순수 함수와 같은 경우 액세스 링크는 최적화될 수 있다. Electrologica X8과 이후의 Burroughs 대형 시스템과 같은 일부 구형 컴퓨터는 중첩 함수를 지원하기 위해 특수 "디스플레이 레지스터"를 가지고 있었지만, 대부분의 최신 컴퓨터(예: 널리 사용되는 x86)용 컴파일러는 필요에 따라 스택에 포인터용으로 몇 단어를 예약한다.
4. 구조
콜 스택은 스택 프레임(또는 활성화 레코드)이라는 단위로 구성된다. 각 스택 프레임은 하나의 서브루틴 호출에 해당하며, 일반적으로 다음과 같은 정보를 포함한다.[1]
- 루틴에 전달된 인수 (매개변수 값)
- 루틴 호출자에게 다시 반환하는 주소
- 루틴의 지역 변수를 위한 공간
콜 스택을 사용하는 주된 목적은 서브루틴 처리 완료 후 제어를 반환할 위치(반환 주소)를 기억하는 것이다.[7]
어떤 서브루틴에 관한 정보를 콜 스택에 올리는 것을 와인드(winding, 감기)라고 하고, 반대로 그것을 삭제하는 것을 언와인드(unwinding, 풀기)라고 부른다.
콜 스택에 할당된 영역을 다 사용하면 "스택 오버플로우"라고 불리는 런타임 오류가 발생한다.
하나의 실행 중인 프로그램 (더 정확히는 스레드)에는 하나의 콜 스택이 대응하여 존재한다.
저수준 언어 (어셈블리 언어)에서는 프로그래머가 명시적으로 스택을 조작해야 한다. 반면, 고수준 언어에서는 콜 스택은 투명하다. 즉, 프로그래머는 콜 스택의 존재를 의식하지 않고 호출 계층 구조에 의해 실현되는 상위 개념으로서의 프로그램 로직에만 집중할 수 있다.
각 프로그래밍 언어에서의 스택의 상세 정보는 컴파일러, OS, 명령어 집합 등에 의존한다.
4. 1. 스택 프레임
'''스택 프레임'''(stack frame) 또는 '''활성화 레코드'''(activation record)는 머신 종속적이며 ABI에 종속적인 서브루틴 상태 정보를 담고 있는 데이터 구조이다. 각 스택 프레임은 아직 반환으로 종료되지 않은 서브루틴 호출에 해당한다. 예를 들어, `DrawLine`이라는 서브루틴이 `DrawSquare` 서브루틴에 의해 호출되어 현재 실행 중이라면, 콜 스택의 상단 부분은 인접한 그림과 같이 배치될 수 있다.
콜 스택은 '''스택 프레임'''들로 구성된다. 스택의 맨 위에 있는 스택 프레임은 현재 실행 중인 루틴에 대한 것이며, 프레임 내의 정보 (예: 매개변수 또는 지역 변수)에 어떤 순서로든 접근할 수 있다.[1]
일반적으로 스택 프레임은 최소한 다음 항목들을 포함한다(푸시 순서대로):
- 루틴에 전달된 인수(매개변수 값)(있는 경우).
- 루틴 호출자에게 다시 반환하는 주소(예: `DrawLine` 스택 프레임에서 `DrawSquare`의 코드 주소).
- 루틴의 지역 변수를 위한 공간(있는 경우).
대부분의 시스템에서 스택 프레임은 호출자가 실행되는 동안 가지고 있던 값, 즉 이전 프레임 포인터 레지스터의 값을 담는 필드를 추가로 가지고 있다. 예를 들어, `DrawLine`의 스택 프레임은 `DrawSquare`가 사용하는 프레임 포인터 값을 저장하는 메모리 위치를 갖게 된다 (위 그림에는 표시되지 않음). 이 값은 서브루틴에 진입할 때 저장된다. 스택 프레임의 알려진 위치에 이러한 필드가 있으면 코드는 현재 실행 중인 루틴의 프레임 아래에 있는 각 프레임에 차례로 접근할 수 있으며, 루틴이 반환하기 직전에 프레임 포인터를 ''호출자''의 프레임으로 쉽게 복원할 수 있다.
어떤 목적을 위해, 서브루틴의 스택 프레임과 이를 호출한 측의 스택 프레임은 겹쳐진다고 간주될 수 있으며, 이 겹침은 호출자가 피호출자에게 매개변수를 전달하는 영역으로 구성된다. 일부 환경에서, 호출자는 각 인수를 스택에 푸시하여 스택 프레임을 확장한 다음 피호출자를 호출한다. 다른 환경에서는 호출자가 호출하는 다른 서브루틴에 제공하는 인수를 보관하기 위해 스택 프레임 상단에 미리 할당된 영역을 갖는다. 이 영역은 때때로 '발신 인수 영역' 또는 '호출 영역'이라고 한다. 이 접근 방식에 따라, 해당 영역의 크기는 컴파일러가 호출된 모든 서브루틴에 필요한 가장 큰 크기로 계산한다.
4. 2. 스택 포인터와 프레임 포인터
콜 스택은 스택 자료구조로 구성되어 있어, 함수 호출 시 반환 주소를 스택에 푸시(push)하고, 함수 종료 시 스택에서 반환 주소를 팝(pop)하여 해당 주소로 복귀한다. 이러한 과정을 통해 함수 호출 및 반환이 순차적으로 이루어지며, 스택이 가득 차면 스택 오버플로 오류가 발생한다.콜 스택은 스택 프레임(또는 액티베이션 레코드)으로 구성되며, 각 스택 프레임은 아직 종료되지 않은 서브루틴 호출에 대한 정보를 담고 있다. 스택 프레임에는 일반적으로 다음 정보가 포함된다.
- 호출된 함수에 전달된 인수 (매개변수 값)
- 호출한 함수로 돌아갈 반환 주소
- 함수의 지역 변수를 위한 공간
스택 프레임의 맨 위는 현재 실행 중인 함수에 해당하며, 이 프레임 내의 정보(매개변수, 지역 변수 등)에 접근할 수 있다.[1]
함수 프레임의 크기는 함수마다 다를 수 있으며, 함수 반환 시 스택 포인터(SP)는 프레임 포인터(FP) 값으로 복원된다. 프레임 포인터는 함수 호출 직전의 스택 포인터 값을 가리킨다.[2] 각 스택 프레임은 바로 아래 프레임의 맨 위를 가리키는 스택 포인터를 포함하며, 스택 포인터는 모든 호출 간에 공유되는 가변 레지스터이다.
대부분의 시스템에서 스택 프레임은 호출자가 실행되는 동안 가지고 있던 값, 즉 이전 프레임 포인터 레지스터의 값을 저장한다. 이를 통해 현재 실행 중인 함수 프레임 아래의 각 프레임에 순차적으로 접근하고, 함수 반환 직전에 프레임 포인터를 호출자의 프레임으로 복원할 수 있다.
콜 스택의 주된 목적은 서브루틴 처리 완료 후 제어를 반환할 위치(반환 주소)를 기억하는 것이다.[7]
5. 동작 방식
콜 스택은 함수의 호출과 반환을 관리하는 데 사용되는 스택 자료구조이다. 함수 호출 시 해당 함수의 정보(반환 주소, 지역 변수, 매개변수 등)가 콜 스택에 쌓이고(push), 함수가 반환될 때 해당 정보가 스택에서 제거(pop)된다.
함수 호출 시, 콜 스택에는 다음과 같은 정보들이 저장된다.
- 반환 주소: 함수 실행이 완료된 후 돌아갈 위치(주소)이다. 이를 통해 호출한 함수로 제어가 다시 넘어갈 수 있다.
- 지역 변수: 함수 내에서만 사용되는 변수들로, 함수가 반환되면 값이 유지되지 않는다.
- 매개변수: 호출하는 코드에서 함수에게 전달하는 값들이다.
- 둘러싸는 서브루틴 컨텍스트: 파스칼, 에이다와 같은 일부 프로그래밍 언어에서, 중첩 함수가 외부 함수의 변수 및 매개변수에 접근할 수 있도록 하는 정보이다.
- 기타 반환 상태: 권한 수준, 예외 처리 정보, 산술 모드 등 함수 반환 시 복원해야 하는 상태 정보가 포함될 수 있다.
함수 반환 시에는 콜 스택에서 해당 함수의 정보(스택 프레임)가 제거되고, 저장된 반환 주소를 통해 호출한 함수로 돌아간다.
C++과 같은 객체 지향 언어에서는 매개변수 목록에 `this` 포인터가 포함될 수 있다.
산술 또는 논리 연산의 피연산자는 대부분 레지스터에 배치되어 연산되지만, 상황에 따라 레지스터 스필링이 발생하여 콜 스택의 공간을 차지하는 평가 스택이 사용될 수 있다.
일부 언어(예: ALGOL 60, PL/I)에서 프로시저 내의 블록은 블록 진입 시 할당되고 블록 종료 시 해제되는 자체 지역 변수를 가질 수 있으며, 블록 종료 시 비활성화되는 자체 예외 처리기를 가질 수 있다.
포스 프로그래밍 언어에서는 반환 주소, 루프 매개변수, 인덱스, 지역 변수 등이 콜 스택(해당 환경에서는 '반환 스택')에 저장되며, 매개변수는 별도의 데이터 스택 또는 매개변수 스택에 저장된다. 또한 부동 소수점 매개변수를 위한 세 번째 스택을 가지기도 한다.
파스칼에서는 중첩된 함수에서 외부 함수로 제어를 전송하는 전역 goto 문을 지원하며, 이 경우 스택 언와인딩이 필요하다. C에는 비지역 goto 역할을 하는 `setjmp` 및 `longjmp` 함수가 있다. Common Lisp는 `unwind-protect` 특수 연산자를 사용하여 스택 언와인딩 시 발생하는 상황을 제어한다.
연속을 적용하면 스택이 언와인딩된 후 연속체의 스택으로 다시 와인딩된다. Scheme 프로그래밍 언어는 연속체가 호출될 때 제어 스택의 언와인딩 또는 리와인딩에서 지정된 지점에서 임의의 thunk를 실행할 수 있다.
6. 사용 예시
다음은 의사 코드를 사용하여 콜 스택의 동작 방식을 보여주는 예시이다. `DrawSquare` 함수가 호출되면, 각 `DrawLine` 호출마다 반환 주소가 콜 스택에 저장되고, `DrawLine` 함수가 종료될 때마다 저장된 반환 주소를 사용하여 `DrawSquare` 함수의 다음 명령으로 복귀한다.
```
subroutine DrawSquare(Point p1, Point p2, Point p3, Point p4)
{
... 생략 ...
DrawLine(p1, p2);
DrawLine(p2, p3);
DrawLine(p3, p4);
DrawLine(p4, p1);
... 생략 ...
}
```
위 의사 고급 프로그래밍 언어의 코드에서 서브루틴 `DrawSquare` 내의 4곳에서 직선을 그리는 서브루틴 `DrawLine`을 호출한다고 할 때, `DrawLine`은 4곳 중 어디로 돌아가야 하는지를 알아야 한다. 일반적으로 `DrawSquare` 코드 내에서 `DrawLine`을 호출하는 각 위치에서 호출 처리의 다음 명령의 주소 (이것을 리턴 주소라고 부른다)를 콜 스택에 저장함으로써 이를 실현한다.
7. 스택 오버플로
콜 스택은 스택으로 구성되어 있어, 호출 측은 반환 주소를 스택에 ''push''하고, 호출된 서브루틴이 완료되면 반환 주소를 콜 스택에서 ''pop''하여 해당 주소로 제어를 반환한다. 호출된 서브루틴이 또 다른 서브루틴을 호출하는 경우에도, 반환 주소를 콜 스택에 push하고, 프로그램에 기록된 대로 정보를 스택에 쌓거나 빼낸다. 어떤 서브루틴에 관한 정보를 콜 스택에 올리는 것을 '''와인드'''('''winding''', '''감기''')라고 하고, 반대로 그것을 삭제하는 것을 '''언와인드'''('''unwinding''', '''풀기''')라고 부른다.
콜 스택에 할당된 영역을 모두 사용하면 "스택 오버플로"라는 런타임 오류가 발생한다. 스택 오버플로는 프로그램의 비정상 종료를 유발하는 심각한 오류이다. 스택 오버플로가 발생했을 때의 동작은 프로그래밍 언어나 실행 환경에 따라 다르지만, 통상 프로그램의 비정상 종료와 같은 미정의 동작을 일으키며, 회복 불가능한 경우가 많다.
소프트웨어를 정상적으로 동작시키기 위해서는 콜 스택을 올바르게 유지하는 것이 중요하다. 콜 스택의 용량은 데스크톱 운영 체제 환경에서도 기본적으로 (스레드마다) 수 MiB 정도밖에 안 되며, 임베디드 환경에서는 더욱 제한이 심하다. 고수준 언어에서는 평소 콜 스택의 존재를 의식하지 않아도 되기 때문에, 힙이 아닌 스택에 거대한 배열을 확보하여 용량을 모두 사용해 버리고 스택 오버플로를 발생시키는 것과 같은 초보적인 실수를 범하는 경우도 있다.
8. 성능 분석
프로그램의 성능 프로파일링을 위해 정기적으로 콜 스택 샘플을 채취할 수 있다. 특정 서브루틴의 주소가 콜 스택 샘플링 데이터에 자주 나타난다면, 이는 코드 병목 현상일 가능성이 높으므로 성능 문제를 검사해야 한다.[5]
콜 스택 표본을 무작위로 채취하여 프로그램 성능 최적화에 활용할 수 있다. 콜 스택 상에 자주 나타나는 서브루틴은 빈번하게 호출되거나 1회 실행에 시간이 오래 걸린다고 예상할 수 있으며, 해당 호출 횟수를 줄이거나 1회 실행 시간을 단축하면 큰 효과를 기대할 수 있다.
9. 보안
자유 포인터 또는 배열 쓰기에 대한 검사가 없는 언어(예: C)에서는 코드 실행에 영향을 미치는 제어 흐름 데이터(반환 주소 또는 저장된 프레임 포인터)와 간단한 프로그램 데이터(매개변수 또는 반환 값)가 콜 스택에 혼합되는 것이 보안상 위험하며, 가장 일반적인 유형의 버퍼 오버플로우인 스택 버퍼 오버플로우를 통해 악용될 수 있다.[6]
이러한 공격 중 하나는 임의의 실행 가능한 코드로 버퍼를 채우고, 이 버퍼 또는 다른 버퍼를 오버플로우하여 일부 반환 주소를 실행 가능한 코드를 직접 가리키는 값으로 덮어쓰는 것이다. 결과적으로 함수가 반환될 때 컴퓨터는 해당 코드를 실행한다. 이러한 종류의 공격은 W^X로 차단할 수 있지만, return-to-libc 공격 또는 리턴 지향 프로그래밍과 같이 W^X 보호가 활성화되어 있어도 유사한 공격이 성공할 수 있다. 배열을 반환 스택과 완전히 별도의 위치에 저장하는 등 다양한 완화책이 제안되었다.[6]
참조
[1]
웹사이트
Stack frames
https://people.cs.ru[...]
2018-02-16
[2]
웹사이트
Understanding the Stack
http://www.cs.umd.ed[...]
2003-06-22
[3]
문서
AlternativeMicroprocessorDesign
[4]
간행물
Call Stack Coverage for GUI Test-Suite Reduction
http://www.cs.umd.ed[...]
[5]
웹사이트
Debugging with GDB: Examining the Stack
http://www.chemie.fu[...]
1997-10-17
[6]
문서
The Forth Programming Language - Why YOU should learn it
http://www.hcsw.org/[...]
[7]
문서
Interstage Application Server/Interstage Web Server チューニングガイド - 7.1.4 スタック
https://software.fuj[...]
[8]
문서
x64 calling convention | Microsoft Learn
https://learn.micros[...]
[9]
문서
"/STACK (Stack allocations) | Microsoft Learn"
https://learn.micros[...]
[10]
문서
Threading Programming Guide - Thread Management | Apple Developer Documentation Archive
https://developer.ap[...]
[11]
간행물
“Call Stack Coverage for GUI Test-Suite Reduction”
2006-11
[12]
간행물
“Call-Stack Coverage for GUI Test-Suite Reduction”
IEEE Press
2008
본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.
문의하기 : help@durumis.com